package chen;


import sun.misc.Unsafe;

import java.lang.reflect.Field;

/**
 * 仅实现了acquerd
 */
public class SimpleAQS3 {
    //表示头元素
    private volatile Node head;
    //表示尾元素
    private volatile Node tail;
    //status为1表示锁被占用，0表示锁空闲
    private volatile int status;

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    private Thread exclusiveOwnerThread;

    public Thread getExclusiveOwnerThread() {
        return exclusiveOwnerThread;
    }

    public void setExclusiveOwnerThread(Thread exclusiveOwnerThread) {
        this.exclusiveOwnerThread = exclusiveOwnerThread;
    }

    public final void acquire(int arg) {
        /**
         * 1. 如果tryAcquire返回true, 则说明已经获取到锁, 则不执行后面的程序 (创建队列, 创建Node元素, 排队)
         * 2. 如果tryAcquire返回false, 则说明锁被占用, 则执行后面的程序进行排队
         * */


        if (!tryAcquire(arg) && acquireQueued(addWaiter(), arg)) {
            Thread.currentThread().interrupt(); // 自我中断
        }

    }

    /*
     * 判断传入的Node是否需要排队, 如果需要排队, 则开始排队, 不需要排队则直接获取锁
     * @author GangsterChen
     * @date 2021/3/22 19:06
     * @param [node, arg]
     * @return 如果排队成功,(线程开始等待) 返回ture,如果没有等待, 则返回false
     */
    private boolean acquireQueued(Node node, int arg) {

        return false;
    }

    /*
     * 根据当前线程, 创建一个Node对, 且将该对象放入队列
     * @author GangsterChen
     * @date 2021/3/22 19:05
     * @param []
     * @return []
     */
    private synchronized Node addWaiter() {
        return null;
    }

    /*
     * 尝试获取锁
     * @author GangsterChen
     * @date 2021/3/22 19:03
     * @param [arg]
     * @return 如果获取到锁, 返回ture 反之false
     */
    private boolean tryAcquire(int arg) {
        // 获取当前线程对象
        Thread thread = Thread.currentThread();
        // 获取当前锁状态
        int status = getStatus();
        if (status == 0) { // 当前锁属于释放状态
            // 首先判断自己是否需要排队, 如果不需要排队, 则直接获取锁, 如果需要排队返回false
            if (!hasQueuedPredecessors() && compareAndSetStatu(0, arg)) {
                // 获取锁成功
                setExclusiveOwnerThread(thread); // 设置占有资源的线程为当前的线程
                System.out.println(thread.getName() + "获取锁成功!");
                return true;
            }
        } else if (thread == getExclusiveOwnerThread()) {
            // 如果当前线程就是占有锁的线程 ( 锁重入 )
            status = getStatus() + arg;
            setStatus(status);
            return true;
        }

        return false;
    }

    // 创建一个unsafe对象
    private static Unsafe unsafe;
    private static long statusOffset = 0;

    static {
        try {
            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            unsafe = (Unsafe) theUnsafe.get(null);
            // 获取status偏移量
            statusOffset = unsafe.staticFieldOffset(SimpleAQS3.class.getDeclaredField("statusOffset"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /*
     * 获取锁 [原子操作] 完成锁状态的修改
     * @author GangsterChen
     * @date 2021/3/22 19:35
     * @param [i, arg]
     * @return 获取成功返回true, 否则返回false
     */
    private boolean compareAndSetStatu(int i, int arg) {
        return unsafe.compareAndSwapLong(this, statusOffset, i, arg);
    }

    /*
     * 判断自己是否需要排队
     * @author GangsterChen
     * @date 2021/3/22 19:36
     * @param []
     * @return 如果返回ture说明要排队, 如果返回false说明可以直接获取锁
     */
    private boolean hasQueuedPredecessors() {
        // 1、队列为空，队列只有一个元素，不需要排队
        // 2、队列正在初始化，排队
        // 3、队列有元素，当前线程正好是head元素的下一个元素，不需要排队
        Node h = head;//头元素
        Node t = tail;//尾元素
        Node s;//头元素的下一个元素
        return h != t &&
                (((s = h.next) == null) || (s.thread != Thread.currentThread()));

    }

    /*
     * 节点类
     * @author GangsterChen
     * @date 2021/3/22 19:05
     * @param
     * @return
     */
    private static class Node {
        Node prev;//指向上一个元素
        Node next;//指向下一个元素
        Thread thread;//当前元素中的线程对象
        int status;//当前线程的状态
        // 定义几个状态常量
        static final int DEFAULT = 0;
        static final int WAIT = 1;
        static final int CANCELLED = -1;

        //准备几个构造方法
        public Node() {
        }

        public Node(Thread thread) {
            this.thread = thread;
        }

        public Node(Thread thread, int status) {
            this.thread = thread;
            this.status = status;
        }
    }
}
